// License:

// Product: RPGRoguelikeEngine .Net
// Author: Robert N. Tenney
// Copyright: April 2009

// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation version 2
// of the License.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

//  This license covers all source code, binaries, and other materials related to this project
//  unless specifically stated otherwise.

using System;
using System.Drawing;
using TenneySoftware.Engine;

namespace TenneySoftware.LevelGenerator.CavernGenerator {
    /// <summary>
    /// Cavern mask class is used to define areas that allow or restrict building of
    /// caverns within a level.
    /// </summary>
    public class CavernMask : MaskBase {
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1814:PreferJaggedArraysOverMultidimensional", MessageId = "Member")]
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1051:DoNotDeclareVisibleInstanceFields")]
        protected bool[,] pMask;

        /// <summary>
        /// Constructor for the Cavern Mask generator.
        /// </summary>
        public CavernMask() : base() {
        }
        
        /// <summary>
        /// A Predefined cavern mask that allows building for the entire level.
        /// </summary>
        /// <param name="size">Size of the level to make the mask for.</param>
        /// <returns>A cavern mask object.</returns>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1814:PreferJaggedArraysOverMultidimensional", MessageId = "Body")]
        public static CavernMask PredefinedMaskDefault(Size size){
            CavernMask temp = new CavernMask();
            temp.SetSize(size);
            bool[,] buffer = new bool[temp.Width, temp.Height];
            for(int y = 0; y < temp.Height; y++){
                for(int x = 0; x < temp.Width; x++){
                    buffer[x,y] = true;
                }
            }
            temp.Mask = buffer;
            return temp;
        }

        /// <summary>
        /// Gets or sets the mask array.
        /// </summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1814:PreferJaggedArraysOverMultidimensional", MessageId = "Member")]
        public bool[,] Mask {
            get {
                return pMask;
            }
            set {
                pMask = value;
            }
        }
        
        /// <summary>
        /// Alias for the GetLocation method. Gives a logical name for checking if an area
        /// can be built on.
        /// </summary>
        /// <param name="x">Location on the x axis to get the mask value at.</param>
        /// <param name="y">Location on the y axis to get the mask value at.</param>
        /// <returns>True if the location can be built on.</returns>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "y")]
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "x")]
        public bool BuildAllowed(int x, int y){
            return this.GetLocation(x, y);
        }
        
        /// <summary>
        /// Alias for the GetLocation method. Gives a logical name for checking if an area
        /// can be built on.
        /// </summary>
        /// <param name="location">Location to get the mask value at.</param>
        /// <returns>True if the location can be built on.</returns>
        public bool BuildAllowed(Point location){
            return this.GetLocation(location);
        }
        
        /// <summary>
        /// Sets a rectagular area to a given value;
        /// </summary>
        /// <param name="area">Rectanular area to set.</param>
        /// <param name="value">Value to set the area to.</param>
        public void SetRectangle(Rectangle area, bool value){
            if(Bounds.Contains(area)){
                for(int y = area.Top; y < area.Height; y++){
                    for(int x = area.Left; x < area.Width; x++){
                        this.pMask[x,y] = value;
                    }
                }
            }
        }

        /// <summary>
        /// Gets the mask value at the given location.
        /// </summary>
        /// <param name="location">Location to get the mask value at.</param>
        /// <returns>boolean value of the mask at the given location.</returns>
        public bool GetLocation(Point location) {
            return this.GetLocation(location.X, location.Y);
        }
        
        /// <summary>
        /// Gets the mask value at the given location.
        /// </summary>
        /// <param name="x">Location on the x axis to get the mask value at.</param>
        /// <param name="y">Location on the y axis to get the mask value at.</param>
        /// <returns>boolean value of the mask at the given location.</returns>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "y")]
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "x")]
        public bool GetLocation(int x, int y) {
            if(IsLocationWithinBounds(x, y)){
                return pMask[x, y];
            } else{
                throw new LocationOutsideOfBoundsException("Location is outside of mask's bounds of: " + this.Size.ToString() + " ("+new Point(x, y).ToString() + ").");
            }
            
        }
        
        /// <summary>
        /// Sets the mask value of a specified value at the given loction.
        /// </summary>
        /// <param name="location">Location to set the value at.</param>
        /// <param name="value">Value to set.</param>
        public void SetLocation(Point location, bool value){
            this.SetLocation(location.X, location.Y, value);
        }
        
        /// <summary>
        /// Sets the mask value of a specified value at the given loction.
        /// </summary>
        /// <param name="x">Location on the x axis to set the value at.</param>
        /// <param name="y">Location on the y axis to set the value at.</param>
        /// <param name="value">Value to set.</param>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "y")]
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Naming", "CA1704:IdentifiersShouldBeSpelledCorrectly", MessageId = "x")]
        public void SetLocation(int x, int y, bool value){
            if(IsLocationWithinBounds(x, y)){
                this.pMask[x,y] = value;
            }
        }
        
        /// <summary>
        /// Tests whether the given location is within the level bounds or not.
        /// </summary>
        /// <param name="x">X-axis location.</param>
        /// <param name="y">Y-axis location.</param>
        /// <returns>True if within bounds, false otherwise.</returns>
        private bool IsLocationWithinBounds(int x, int y){
            return Bounds.Contains(x, y);
        }
    }
}
